A "remote procedure call" (RPC) refers to a procedure or function call initiated by a computer program ("caller") of another computer program ("callee"), where the two computer programs are in separate address spaces. After invoking the function, the results of the invocation (e.g., success or failure) are usually returned to the caller.
FIG. 1 depicts a block diagram of a conventional system for performing remote procedure calls. The conventional RPC system, as depicted in FIG. 1, has a client 102 and a server 104. The client 102 and the server 104 are separate computer systems that are interconnected. Both the client 102 and the server 104 contain an operating system 106, 120, and an RPC runtime facility 108, 122 that contains a virtual function table ("VT") 110, 124. In addition, the client 102 and the server 104 contain two application programs 112, 114 and 126, 128, and one RPC stub for each application program 116, 118, 130, 132. The operating systems 106, 120 are responsible for managing system resources. The RPC runtime facilities 108, 122 serve to transfer a remote procedure call from the client 102 to the server 104 and to return results of the remote procedure call from the server to the client. The RPC runtime facilities 108, 122 contain a virtual function table 110, 124 and look-up information that is used to locate the function being invoked by the remote procedure call. The application programs 112, 114 request the invocation of functions that are local to application programs 126, 128. The RPC stubs 116, 118 of the client 102 are usually referred to as "client stubs" and provide functions that have similar signatures to functions contained within application programs 126, 128. The "signature" of a function refers to the specific arguments, function name and return code for the function. Thus, by providing a similar signature, the client stubs 116, 118 make it appear to the application programs 112, 114 that the invocation of-the function is local. Although the client stubs 116, 118 make it appear to the application programs 112, 114 that the invocation of the function is local, the client stubs actually translate the function call into a number of calls to the RPC runtime facility 108 so as to interface with the RPC runtime and invoke the function remotely. The RPC stubs 130, 132 of the server 104 are usually referred to as "server stubs" and receive information from the RPC runtime facility 122 sufficient to create a local function call. After completion of the function call, the server stubs 130, 132 return results to the RPC runtime facility 122 which in turn sends the results back to the caller.
The RPC runtime facility utilizes a buffer ("runtime buffer") to send data associated with the RPC (e.g., arguments) from the client to the server as well as to return results from the server to the client. An "argument" is a parameter of a function. The RPC stubs of the client and the server contain both code and data that are used together to interface with the RPC runtime. The code of RPC stubs copies arguments for a particular function into the runtime buffer (this process is known as "marshaling") as well as copies arguments out of the runtime buffer (this process is known as "unmarshaling"). When copying the arguments into the runtime buffer, the arguments are laid out in a format specific to the runtime buffer, whereas the functions typically use the arguments in a different format. The code of the RPC stubs includes information necessary to create an argument stack for a particular function. An "argument stack" refers to a buffer that contains arguments for the function in a specific order, with each argument having a specific size, type and value. The information necessary for creating the argument stack ("format information") is determined at compile time and includes the order of the arguments, the size of the arguments and the type of the arguments. The values of the arguments are typically dead at runtime. The argument stack is usually a necessary component of a function invocation.
In many conventional systems, RPC stubs are created by an interface definition language ("IDL") compiler. The IDL compiler understands a language that is used to define functions and their signatures. A user utilizes an IDL compiler by first creating an IDL file that contains the signatures of a number of functions that are to be invoked remotely. Then, the user invokes the IDL compiler to compile the IDL file into C or C++ code. Lastly, the user invokes a C or C++ compiler to generate machine code that serves as the RPC stubs to be utilized by application programs when performing RPCs.
There are various different types of arguments that are utilized within an RPC system. These types of arguments fall into four categories: base types, pointer types, homogeneous types and heterogeneous types. The "base types" category includes standard C data types, such as long, int, short and char. The "pointer types" category refers to references to the standard C base types. In addition to referring to C base types, pointer types are directional in nature and can be specified to be an "in" pointer, an "in/out" pointer or an "out" pointer. The "in" directional pointer is a pointer that is being passed into the function that references data to be used by the invoked function but will be disregarded after the execution of the function. Therefore, an in argument need only be transferred from the client to the server. An "in/out" directional pointer is a pointer that references data that will be passed in to be utilized by a remote function and will also be utilized by the caller upon return of the function. Thus, in/out arguments are transferred from the client to the server as well as from the server to the client. An "out" directional pointer refers to data that is utilized by the caller upon return of the function. As such, an out argument is transferred from the server to the client. In addition to the directionality of a pointer, pointers can refer to conformant or varying objects. A "conformant object" is an object whose size is determined at runtime, such as a conformant array that is allocated at runtime. When a conformant object is utilized as an argument, another argument follows the conformant object known as a "specifier argument" that specifies the size of the conformant object. A "varying object" is an object whose size is known at compile time, but the range of usable elements is determined at runtime, such as occurs when passing a subset of elements of an array as an argument. When utilizing a varying object as an argument, a specifier argument is utilized to specify the range of elements within the varying object. The homogeneous type refers to a grouping of similar data types, such as an array of integers. The heterogeneous type refers to a grouping of dissimilar data types, such as a structure or a union.
In performing an RPC by the conventional system depicted in FIG. 1, a calling application program within the client invokes the client stub that has a similar signature to a remote function that the calling application program wishes to invoke. To the caller, it appears as if the invocation of the remote function occurs locally. The client stub receives arguments as part of the invocation and sizes the arguments. When sizing the arguments, the client stub determines the size of each argument and when encountering a pointer, determines the size of the data that is referenced by the pointer. The client stub then allocates a buffer of the determined size from the RPC runtime facility, thus creating a runtime buffer, and copies the "in" and "in/out" arguments into the buffer. After copying the arguments into the buffer, the client stub o the client side RPC runtime facility to send the runtime buffer to the server side RPC runtime facility. When the server side RPC runtime facility receives the runtime buffer, the server side RPC runtime facility accesses the virtual function table to determine the application program that the requested function. The server side RPC runtime facility then passes the runtime buffer to a server stub of the destination application program. The server stub copies the data and directly invokes the function. When copying the data, the server stub takes the arguments out of the RPC runtime buffer and stores them into a buffer according to the format information of the argument stack that was created at compile time, thereby creating an argument stack. After storing the arguments, the server stub invokes the function with the argument stack and upon completion of the function, receives the results (i.e., in/out arguments, out arguments and a return value). The server stub then determines the size of the results, allocates a runtime buffer of this size and copies the results into the buffer. Only in/out arguments, out arguments and a return value are processed since this is the only data returned to the caller. After copying the results into the runtime buffer, the runtime buffer is sent from the server side RPC runtime facility to the client side RPC runtime facility where it is passed to the caller via the client stub.
Using conventional systems for performing RPC leads to the use of significant amounts of storage. This significant storage is in part due to the duplication of RPC stubs throughout the system. Each RPC stub within the system marshals arguments into a runtime buffer and unmarshals arguments out of a runtime buffer. The code for performing this operation is duplicated for each stub in the system. In addition, since all sizing and copying of arguments is specific to the signature of the function being invoked, if two functions have the same signature, the stub for each function is the same, thereby leading to an excessive use of storage.